﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using GalaSoft.MvvmLight.Messaging;
using SuperSocket;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
using SuperSocket.SocketBase.Protocol;
using VisionApp.Entity;
using VisionApp.Interface;

namespace VisionApp.NetService
{
    /// <summary>
    /// This class is designed as the common socket server to be used in socket communication.
    /// </summary>
    public class SuperSocketServer
    {
        private Logger _log;

        // 服务器IP
        private string serverIPAddress;

        // 服务器端口号
        private int serverIPPort;

        private string _clientIp;

        // 存储session和对应ip端口号的泛型集合
        private readonly Dictionary<string, AppSession> sessionList = new Dictionary<string, AppSession>();

        // AppServer 代表了监听客户端连接，承载TCP连接的服务器实例。理想情况下，我们可以通过AppServer实例获取任何你想要的客户端连接，服务器级别的操作和逻辑应该定义在此类之中。
        private TerminatorProtocolServer appServer;

        /// <summary>
        /// Initializes a new instance of the <see cref="SuperSocketServer"/> class.
        /// </summary>
        /// <param name="serverIP">server ip to be binded.</param>
        /// <param name="serverPort">server port to be binded.</param>
        public SuperSocketServer()
        {
            _log = new Logger();
        }

        /// <summary>
        /// Gets the value to used to represent the session list.
        /// </summary>
        public Dictionary<string, AppSession> SessionList => this.sessionList;

        /// <summary>
        /// Build Socket server and initialize the callback event.
        /// </summary>
        /// <returns>true if build success.</returns>
        public bool BuildServer(string serverIP, int serverPort)
        {
            this.serverIPAddress = "any";
            this.serverIPPort = serverPort;
            bool buildResult = false;
            if (this.appServer == null || this.appServer?.State != ServerState.Running)
            {
                this.appServer = new TerminatorProtocolServer();

                // 具体设置，第三方类库SuperSocket参考URL: https://docs.supersocket.net/v1-6/zh-CN
                var se = new ServerConfig
                {
                    Ip = this.serverIPAddress,
                    Port = this.serverIPPort,
                    MaxConnectionNumber = 1000,
                    SendBufferSize = 4096,
                    ReceiveBufferSize = 4096,
                    Mode = SocketMode.Tcp,
                };

                if (!this.appServer.Setup(se))
                {
                    return buildResult;
                }

                if (!this.appServer.Start())
                {
                    return buildResult;
                }

                this.appServer.SessionClosed += this.AppServer_SessionClosed;

                this.appServer.NewSessionConnected += this.AppServer_NewSessionConnected;

                this.appServer.NewRequestReceived += this.AppServer_NewRequestReceived;

                buildResult = true;
            }
            else
            {
                buildResult = true;
            }

            return buildResult;
        }

        /// <summary>
        /// Send message to a specifed client.
        /// </summary>
        /// <param name="clientIp">client ip.</param>
        /// <param name="message">client message.</param>
        /// <returns>true if send the message.</returns>
        public bool SendMessage(string clientIp, string message)
        {
            if (this.sessionList.TryGetValue(clientIp, out AppSession appSession))
            {
                return appSession.TrySend(message);
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Stop the server.
        /// </summary>
        public void StopServer()
        {
            this.appServer.Stop();
            this.appServer.Dispose();
        }

        private void AppServer_NewRequestReceived(AppSession session, StringRequestInfo requestInfo)
        {
            // session 是客户端。
            // requestInfo.Key 是请求的命令行用空格分隔开的第一部分.
            // requestInfo.Body 是请求的命令行用空格分隔开的第二部分.
            // 客户端发送过来的消息保存在 requestInfo.Body中。
            // 客户端发送消息需要加上\r\n
            double[] data;
            var messageKey = requestInfo.Key;
            var clientMessage = requestInfo.Body;
            _log.Imformation($"receive a msg: messageKey is {messageKey}, clientMessage is {clientMessage}");
            parseRecvStr(clientMessage, out data);
            RobDataMediaType robData = new RobDataMediaType();
            robData.Msg.ClientIp = session.RemoteEndPoint?.ToString();
            robData.MsgType = MsgTypeEnum.RobData;
            robData.Msg.Name = (RobCmdEnum)Convert.ToInt32(messageKey);
            if(robData.Msg.Name== RobCmdEnum.BarCode)
            {
                robData.Msg.Str = clientMessage;
            }
            else
            {
                robData.Msg.Data = data;
            }
            
            Messenger.Default.Send<RobDataMediaType>(robData);
            Console.Write(messageKey);
        }

        private void AppServer_NewSessionConnected(AppSession session)
        {
            var clientIp = session.RemoteEndPoint?.ToString();
            if (string.IsNullOrEmpty(clientIp))
            {
                return;
            }

            if (this.sessionList.TryGetValue(clientIp, out AppSession appSession))
            {
                this.sessionList[clientIp] = session;
            }
            else
            {
                this.sessionList.Add(clientIp, session);
            }
            Messenger.Default.Send<string>("client connected "+ clientIp);
            Messenger.Default.Send<RobotStatus>(RobotStatus.CONNECTED);
        }

        private void AppServer_SessionClosed(AppSession session, CloseReason value)
        {
            var clientIp = session.RemoteEndPoint?.ToString();
            if (string.IsNullOrEmpty(clientIp))
            {
                return;
            }

            if (this.sessionList.TryGetValue(clientIp, out AppSession appSession))
            {
                this.sessionList.Remove(clientIp);
            }
            Messenger.Default.Send<string>("client disconnected " + clientIp);
            Messenger.Default.Send<RobotStatus>(RobotStatus.DISCONNECT);
        }

        private bool parseRecvStr(string rawData, out double[] data)
        {
            try
            {
                string[] data_str = rawData.Split(',');
                data = new double[data_str.Length];
                for (int i = 0; i < data_str.Length; i++)
                {
                    data[i] = Convert.ToInt32(data_str[i]);
                }
                return true;
            }
            catch (Exception e)
            {
                data = new double[1];
                return false;
            }
        }
    }

    /// <summary>
    /// TerminatorProtocolServer
    /// Each request end with the terminator "\r"
    /// ECHO Your message\r
    /// </summary>
    public class TerminatorProtocolServer : AppServer
    {
        public TerminatorProtocolServer()
            : base(new TerminatorReceiveFilterFactory("\r", Encoding.Default, new BasicRequestInfoParser(",", ",")))
        {

        }
    }
}